package api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

const (
	chatUrl   = "https://www.sophnet.com/api/open-apis/v1/chat/completions"
	serviceId = "uk5gQl9dXNVzV7nOOYe0J"
)

type ChatCompletionRequest struct {
	Messages []Message `json:"messages"`
	Model    string    `json:"model"`
	Stream   bool      `json:"stream,omitempty"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type ChatCompletionResponse struct {
	Object  string    `json:"object"`
	Created int       `json:"created"`
	Model   string    `json:"model"`
	Choices []Choices `json:"choices"`
}

type Choices struct {
	Index        int     `json:"index"`
	FinishReason string  `json:"finish_reason"`
	Message      Message `json:"message"`
}

func SendChatCompletionRequest(apiKey, model string, messages []Message) (*ChatCompletionResponse, error) {
	requestData := ChatCompletionRequest{
		Messages: messages,
		Model:    model,
	}
	requestBody, err := json.Marshal(requestData)
	if err != nil {
		return nil, fmt.Errorf("encode request error: %v", err)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", chatUrl, bytes.NewBuffer(requestBody))
	if err != nil {
		return nil, fmt.Errorf("create request error: %v", err)
	}
	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("send request error: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API return status code: %d, response: %s", resp.StatusCode, string(body))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read response body: %v", err)
	}

	// fmt.Printf("response: %s\n", string(body))

	var response ChatCompletionResponse
	err = json.Unmarshal(body, &response)
	if err != nil {
		return nil, fmt.Errorf("decode json response error: %v", err)
	}

	return &response, nil
}

func ParseAIResponse(response string) (int, []string) {
	parts := strings.SplitN(response, ",", -1)
	if len(parts) < 2 {
		return 0, []string{}
	}
	parts = parts[1:]
	fileNames := []string{}
	for _, part := range parts {
		trimmedPart := strings.TrimSpace(part)
		if trimmedPart != "" {
			fileNames = append(fileNames, trimmedPart)
		}
	}
	return len(fileNames), fileNames
}

func UploadRequest(apiKey, model string, filePaths []string, messages []Message) (*ChatCompletionResponse, error) {
	messages[1].Content += "，请参考下面上传的文件内容 \n上传文件: \n"
	for i, filePath := range filePaths {
		if filePath != "" {
			messages[1].Content += "上传文件" + strconv.Itoa(i) + ":\n"
			filePath = strings.TrimSpace(filePath)
			file, err := os.Open(filePath)
			if err != nil {
				return nil, fmt.Errorf("open file error: %v", err)
			}
			defer file.Close()

			fileContent, _ := io.ReadAll(file)
			messages[1].Content += string(fileContent) + "\n"
		}
	}
	// fmt.Println("message: ", messages)
	return SendChatCompletionRequest(apiKey, model, messages)
}

func addPwd(input *string) {
	*input += "\n当前操作系统: " + runtime.GOOS + "\n"
	*input += "\n当前目录:\n"
	currentDir, err := os.Getwd()
	if err == nil {
		*input += currentDir
	}
}

func addTree(input *string) {
	var (
		wd      string
		dirInfo string
		err     error
	)
	if wd, err = os.Getwd(); err != nil {
		return
	}
	if dirInfo, err = printDirTree(wd, 0); err != nil {
		return
	}
	*input += "\n当前目录下的层级结构:\n"
	*input += dirInfo
}

func printDirTree(path string, level int) (string, error) {
	var builder strings.Builder
	entries, err := os.ReadDir(path)
	if err != nil {
		return "", err
	}

	for i, entry := range entries {
		if entry.Name()[0] == '.' {
			continue
		}
		for j := 0; j < level; j++ {
			builder.WriteString("│   ")
		}
		if i == len(entries)-1 {
			builder.WriteString("└── ")
		} else {
			builder.WriteString("├── ")
		}
		builder.WriteString(entry.Name())
		builder.WriteString("\n")

		if entry.IsDir() {
			subPath := filepath.Join(path, entry.Name())
			subTree, err := printDirTree(subPath, level+1)
			if err != nil {
				return "", err
			}
			builder.WriteString(subTree)
		}
	}
	return builder.String(), nil
}
